package com.cicadalane.androlate;

/*
 * Copyright (C) 2011 cicada.software@gmail.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Hashtable;

import org.json.JSONArray;
import org.json.JSONObject;

public class GoogleTranslate {

	public static Language[] Languages = new Language[] {
		
		// a subset of languages is translatable,
		// this list should be compared to this the list here
		// http://code.google.com/apis/ajaxlanguage/documentation/#SupportedPairs
		
			new Language("AFRIKAANS", "af"), //
			new Language("ALBANIAN", "sq"),  //
			// not a supported translation pair new Language("AMHARIC", "am"), //
			new Language("ARABIC", "ar"), //
			// not a supported translation pair new Language("ARMENIAN", "hy"),//
			// not a supported translation pair new Language("AZERBAIJANI", "az"), //
			// not a supported translation pair new Language("BASQUE", "eu"), //
			new Language("BELARUSIAN", "be"), //
			// not a supported translation pair new Language("BENGALI", "bn"), //
			// not a supported translation pair  new Language("BIHARI", "bh"),//
			new Language("BULGARIAN", "bg"),//
			// not a supported translation pair new Language("BURMESE", "my"),//
			new Language("CATALAN", "ca"), //
			// not a supported translation pair new Language("CHEROKEE", "chr"),//
			new Language("CHINESE", "zh"),
			new Language("CHINESE_SIMPLIFIED", "zh-CN", "zh-rCN"),
			new Language("CHINESE_TRADITIONAL", "zh-TW", "zh-rTW"),
			new Language("CROATIAN", "hr"), //
			new Language("CZECH", "cs"), //
			new Language("DANISH", "da"), //
			// not a supported translation pair new Language("DHIVEHI", "dv"),
			new Language("DUTCH", "nl"), //
			new Language("ENGLISH", "en"), //
			// not a supported translation pair new Language("ESPERANTO", "eo"),//
			new Language("ESTONIAN", "et"), //
			new Language("FILIPINO", "tl"), //
			new Language("FINNISH", "fi"), //
			new Language("FRENCH", "fr"), //
			new Language("GALICIAN", "gl"),//
			// not a supported translation pair new Language("GEORGIAN", "ka"), //
			new Language("GERMAN", "de"), //
			new Language("GREEK", "el"), //
			// not a supported translation pair new Language("GUARANI", "gn"),//
			// not a supported translation pair new Language("GUJARATI", "gu"),//
			new Language("HEBREW", "iw"),//
			new Language("HINDI", "hi"), //
			new Language("HUNGARIAN", "hu"),//
			new Language("ICELANDIC", "is"), //
			new Language("INDONESIAN", "id"),//
			// not a supported translation pair new Language("INUKTITUT", "iu"),//
			new Language("IRISH", "ga"),//
			new Language("ITALIAN", "it"), //
			new Language("JAPANESE", "ja"),//
			// not a supported translation pair new Language("KANNADA", "kn"),//
			// not a supported translation pair new Language("KAZAKH", "kk"),//
			// not a supported translation pair new Language("KHMER", "km"), //
			new Language("KOREAN", "ko"),//
			// not a supported translation pair new Language("KURDISH", "ku"),//
			// not a supported translation pair new Language("KYRGYZ", "ky"),//
			// not a supported translation pair new Language("LAOTHIAN", "lo"),//
			new Language("LATVIAN", "lv"),//
			new Language("LITHUANIAN", "lt"),//
			new Language("MACEDONIAN", "mk"),//
			new Language("MALAY", "ms"), //
			// not a supported translation pair new Language("MALAYALAM", "ml"),//
			new Language("MALTESE", "mt"), //
			// not a supported translation pair new Language("MARATHI", "mr"),//
			// not a supported translation pair new Language("MONGOLIAN", "mn"), //
			// not a supported translation pair new Language("NEPALI", "ne"),//
			new Language("NORWEGIAN", "no", "nb"), //
			// not a supported translation pair new Language("ORIYA", "or"),//
			// not a supported translation pair new Language("PASHTO", "ps"), //
			new Language("PERSIAN", "fa"),//
			new Language("POLISH", "pl"),//
			new Language("PORTUGUESE (Portugul)", "pt-PT", "pt-rPT"),//
			new Language("PORTUGUESE", "pt-PT", "pt"),//
			// not a supported translation pair new Language("PUNJABI", "pa"), //
			new Language("ROMANIAN", "ro"),//
			new Language("RUSSIAN", "ru"), //
			// not a supported translation pair new Language("SANSKRIT", "sa"),//
			new Language("SERBIAN", "sr"), //
			// not a supported translation pair new Language("SINDHI", "sd"),//
			// not a supported translation pair new Language("SINHALESE", "si"),//
			new Language("SLOVAK", "sk"),//
			new Language("SLOVENIAN", "sl"),//
			new Language("SPANISH", "es"),//
			new Language("SPANISH US", "es", "es-rUS"),//
			new Language("SWAHILI", "sw"),//
			new Language("SWEDISH", "sv"),//
			// not a supported translation pair new Language("TAJIK", "tg"),//
			// not a supported translation pair new Language("TAMIL", "ta"),//
			// not a supported translation pair new Language("TAGALOG", "tl"),//
			// not a supported translation pair new Language("TELUGU", "te"),//
			new Language("THAI", "th"), //
			// not a supported translation pair new Language("TIBETAN", "bo"),//
			new Language("TURKISH", "tr"),//
			new Language("UKRAINIAN", "uk"),//
			// not a supported translation pair new Language("URDU", "ur"), //
			// not a supported translation pair new Language("UZBEK", "uz"),//
			// not a supported translation pair new Language("UIGHUR", "ug"),//
			new Language("VIETNAMESE", "vi"),//
			new Language("WELSH", "cy"), //
			new Language("YIDDISH", "yi") };//
	
	private static final String translate_url_string = "http://ajax.googleapis.com/ajax/services/language/translate";
	private static URL translate_url = null;

	private static String mIpAddress = "";

	public static void setIpAddress(String value) {
		mIpAddress = value;
	}

	public static Hashtable<String, String> languages;
	static {
		languages = new Hashtable<String, String>();

		try {
			translate_url = new URL(translate_url_string);
		} catch (MalformedURLException mue) {
			mue.getStackTrace();
		}
	}

	private static String escapeWorkaround(String s) {
		String result = s.replace("\\", "__backslash__");
		result = result.replace("/", "__forwardslash__");
		result = result.replace("<", "__lessthan__");
		result = result.replace(">", "__greaterthan__");
		result = result.replace(":", "__colon__");
		return result;
	}

	private static String unescapeWorkaround(String s) {
		String result = s.replace("__colon__", ":"); 
		result = result.replace("__greaterthan__", ">");
		result = result.replace("__lessthan__", "<");
		result = result.replace("__forwardslash__", "/");
		result = result.replace("__backslash__", "\\");
		return result;
	}

	public static String translate(final String text,
			final AndrolateLanguage from, final AndrolateLanguage to)
			throws Exception {

		StringBuilder result = new StringBuilder();
		// Google translate has a limit of MAX_STRING_LENGTH characters, so we
		// have to split it into chunks
		ArrayList<String> stringList = new ArrayList<String>();
		if (text.length() > MAX_STRING_LENGTH) {
			String[] chunks = StringUtils.split(text, MAX_STRING_LENGTH);
			for (String c : chunks)
				stringList.add(c);
		} else
			stringList.add(text);

		for (String s : stringList) {
			// google translate has problems with \ characters, so lets escape
			// and replace them
			s = escapeWorkaround(s);			
			GoogleTranslateParameters params = new GoogleTranslateParameters(s,
					from.getISO639_1(), to.getISO639_1(), mIpAddress);
			JSONObject json;
			json = submitRequest(translate_url, params.urlEncode());
			String translatedText = HTMLEntities.unhtmlentities(json
					.getJSONObject("responseData").getString("translatedText"));

			translatedText = unescapeWorkaround(translatedText);
			result.append(translatedText);
		}
		return result.toString();
	}

	public static String[] translate(final String[] text,
			final AndrolateLanguage from, final AndrolateLanguage to)
			throws Exception {

		final String[] responses = new String[text.length];
		final String[] tostr = new String[text.length];
		final String[] fromstr = new String[text.length];
		for (int i = 0; i < text.length; i++) {
			tostr[i] = to.getISO639_1();
			fromstr[i] = from.getISO639_1();
		}

		GoogleTranslateParameters params = new GoogleTranslateParameters(text,
				fromstr, tostr, mIpAddress);
		JSONObject json;
		try {
			json = submitRequest(translate_url, params.urlEncode());
		} catch (Exception ex) {
			return null;
		}

		JSONArray jsonArray = json.getJSONArray("responseData");
		for (int i = 0; i < jsonArray.length(); i++) {
			final JSONObject obj = jsonArray.getJSONObject(i);

			responses[i] = HTMLEntities.unhtmlentities(obj.getJSONObject(
					"responseData").getString("translatedText"));
		}
		return responses;

	}

	private static final int MAX_STRING_LENGTH = 300;

	public static String[] translate(final String[] text,
			final AndrolateLanguage from[], final AndrolateLanguage[] to)
			throws Exception {

		// Google translate has a limit of 500 characters, so we have to split
		// it into chunks
		ArrayList<String> stringList = new ArrayList<String>();
		for (String t : text) {
			if (t.length() > MAX_STRING_LENGTH) {
				String[] chunks = StringUtils.split(t, MAX_STRING_LENGTH);
				for (String c : chunks)
					stringList.add(c);
			} else
				stringList.add(t);
		}
		if (stringList.size() != from.length || from.length != to.length) {
			throw new Exception("each argument must be of the same length");
		}
		/*
		 * if (text.length == 1) { return new String[] { execute(text[0],
		 * from[0], to[0]) }; }
		 */
		final String[] responses = new String[text.length];
		final String[] tostr = new String[to.length];
		final String[] fromstr = new String[from.length];
		for (int i = 0; i < text.length; i++) {
			tostr[i] = to[i].getISO639_1();
			fromstr[i] = from[i].getISO639_1();
		}

		GoogleTranslateParameters params = new GoogleTranslateParameters(text,
				fromstr, tostr, mIpAddress);
		JSONObject json;
		try {
			json = submitRequest(translate_url, params.urlEncode());
		} catch (Exception ex) {
			return null;
		}

		JSONArray jsonArray = json.getJSONArray("responseData");
		for (int i = 0; i < jsonArray.length(); i++) {
			final JSONObject obj = jsonArray.getJSONObject(i);

			responses[i] = HTMLEntities.unhtmlentities(obj.getJSONObject(
					"responseData").getString("translatedText"));
		}
		return responses;

	}

	private static JSONObject submitRequest(final URL url,
			final String parameters) throws Exception {
		final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		conn.setRequestProperty("referer", // UPDATE YOUR REFERER AND UNCOMMENT "http://UPDATEWITHYOURURL");
		conn.setRequestMethod("POST");
		conn.setDoOutput(true);

		final PrintWriter pw = new PrintWriter(conn.getOutputStream());
		pw.write(parameters);
		pw.flush();

		try {
			BufferedReader rd = new BufferedReader(new InputStreamReader(conn
					.getInputStream(), "UTF8"));
			StringBuffer sb = new StringBuffer();
			String line;
			while ((line = rd.readLine()) != null)
				sb.append(line);

			String responseString = sb.toString();
			JSONObject result = new JSONObject(responseString);
			if (result.getString("responseStatus").equals("200")) {
				return result;
			} else {
				throw new Exception("[" + result.getString("responseStatus")
						+ "] " + result.getString("responseDetails"));
			}
		} finally {
			conn.getInputStream().close();
			if (conn.getErrorStream() != null) {
				conn.getErrorStream().close();
			}
			pw.close();
		}
	}
}
